#ifndef __TWEEN_H__
#define __TWEEN_H__

#include <string>
#include <vector>

namespace tween {

	typedef  float(*EaseFun)(float);

	class ITarget {
	public:
		virtual float	getNumber(const std::string& name) = 0;
		virtual void	setNumber(const std::string& name,float num) = 0;
		virtual void*	getPointer(const std::string& name) = 0;
		virtual void	setPointer(const std::string& name,void* p) = 0;
	};

	class Action {

	public:
		Action* next;
		Action* prev;
		EaseFun ease;

		float startTime; // 时间线的时间
		float endTime; // 时间线的时间
		float duration;
		ITarget* target;
	protected:
		bool inited;

	public:
		Action(ITarget* target, float startTime, float duration);
		virtual ~Action();
		
		virtual void setPosition(float position, bool isReverse);
	protected:
		virtual void init(float ratio , bool isReverse);
		virtual void update(float ratio, bool isReverse);
	};



	class RelativeNum:public Action
	{
	private:
		float lastDeltaValue;
		float deltaValue;
		std::string propName;
	public:
		RelativeNum(ITarget* target, float startTime, float duration, float deltaValue, const std::string& propName);
		virtual ~RelativeNum();

	protected:
		virtual void update(float ratio, bool isReverse);
	};


	class AbsoluteNum :public Action
	{
	private:
		float startValue;
		float deltaValue;
		float toValue;
		std::string propName;
	public:
		AbsoluteNum(ITarget* target, float startTime, float duration, float toValue, const std::string& propName);
		virtual ~AbsoluteNum();

	protected:
		virtual void init(float ratio, bool isReverse);
		virtual void update(float ratio, bool isReverse);
	};


	class StepAction :public Action
	{
	private:
		int stepIndex;
		int stepLength;
		std::vector<void*> steps;
		std::string propName;
	public:
		StepAction(ITarget* target, float startTime, float duration, const std::vector<void*>& steps, const std::string& propName);
		virtual ~StepAction();

	protected:
		virtual void update(float ratio, bool isReverse);
	};

	enum ActionType:char {
		None = 0,
		RelNum = 1,
		AbsNum,
		Step,
	};

	struct ActionData
	{
		ActionData(ActionType type, float t, float dur, const std::string& propName, EaseFun ease)
			:type(type), t(t),dur(dur), propName(propName), ease(ease)
		{
		}

		~ActionData()
		{
			int a = 0;
		}
		ActionType type;
		float t; 
		float dur;
		std::string propName;
		EaseFun	ease;
		union Value
		{
			float num = 0;
			void* ptr;
		} v;
	};

	struct TweenOptions {
		int loop = 0;
		bool useTicks = false;
		bool yoyo = false;
		float timeScale = 1;
	};

	 class Tween final 
	{

	public:
		static const long isInTick;
		static const std::string Complete;

	public:
		ITarget* target;
		int loop;
		bool useTicks;
		bool yoyo;
		float timeScale;
		float duration;
		float rawPosition;
		long lastTick;

	private:
		Action* actionHead;
		Action* actionTail;
		float prevTime;
		bool _paused;

	public:
		Tween(ITarget* target, std::vector<ActionData>& frames, TweenOptions& options);
		~Tween();
		void advance(float delta);
		void setPosition(float rawPosition);

		void dispatchEvent(const std::string& eventName);
		void setPaused(bool value);
		bool getPaused();
	private:
		float initActions(std::vector<ActionData>& frames);
	};

}// namespace tween 


#endif // !__TWEEN_H__
